﻿using System;
using System.Linq;
using System.Data.Entity.Database;
using System.Transactions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NpCrm.DataAccess.Repositories;

namespace NpCrm.Domain.Tests
{
    [TestClass]
    public class AddressRepositoryTests
    {
        private TransactionScope _scope;

        [TestInitialize]
        public void TestSetup()
        {
            DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<NpCrm.DataAccess.Core.NpCrmDataContext>());
            _scope = new TransactionScope(TransactionScopeOption.RequiresNew,
                                          new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted });
        }

        [TestCleanup]
        public void TestTeardown()
        {
            if (_scope != null)
                _scope.Dispose();
        }

        public static Address AddFakeAddress()
        {
            using (var addressRepo = new AddressRepository())
            {
                var testAddress = GetMockAddress();
                addressRepo.Add(testAddress);
                addressRepo.Commit();
                Assert.IsTrue(testAddress.AddressId > 0);
                return testAddress;
            }
        }

        [TestMethod]
        public void CanAdd()
        {
            AddFakeAddress();
        }

        [TestMethod]
        public void CanGetById()
        {
            var fakeAddress = AddFakeAddress();
            using (var addressRepo = new AddressRepository())
            {
                var persistedAddress = addressRepo.GetById(fakeAddress.AddressId);
                Assert.IsNotNull(persistedAddress);
                Assert.AreNotSame(fakeAddress, persistedAddress);
                CompareAddresses(fakeAddress, persistedAddress);
            }
        }

        [TestMethod]
        public void CanUpdate()
        {
            var fakeAddress = AddFakeAddress();
            Address updateAddress;
            using (var addressRepo = new AddressRepository())
            {
                updateAddress = addressRepo.GetById(fakeAddress.AddressId);
                updateAddress.AddressLine1 = "123 Monkey Lane";
                updateAddress.AddressLine2 = "Suite 999";
                updateAddress.City = "Chickenville";
                updateAddress.Country = "Farmania";
                updateAddress.IsApartmentOrSuite = true;
                updateAddress.IsHomeAddress = false;
                addressRepo.Commit();
            }
            using (var addressRepo = new AddressRepository())
            {
                var updatedAddress = addressRepo.GetById(updateAddress.AddressId);
                Assert.IsNotNull(updatedAddress);
                Assert.AreNotSame(updateAddress, updatedAddress);
                CompareAddresses(updateAddress, updatedAddress);
            }
        }

        [TestMethod]
        public void CanDelete()
        {
            var fakeAddress = AddFakeAddress();
            using (var addressRepo = new AddressRepository())
            {
                var addressToDelete = addressRepo.GetById(fakeAddress.AddressId);
                addressRepo.Delete(addressToDelete);
                addressRepo.Commit();
            }
            using (var addressRepo = new AddressRepository())
            {
                var shouldBeNull = addressRepo.GetById(fakeAddress.AddressId);
                Assert.IsNull(shouldBeNull);
            }
        }

        [TestMethod]
        public void CanGetByCity()
        {
            var fakeAddress = AddFakeAddress();
            using (var addressRepo = new AddressRepository())
            {
                var persistedAddress = addressRepo.GetByCity(fakeAddress.City).FirstOrDefault();
                Assert.IsNotNull(persistedAddress);
                Assert.AreNotSame(fakeAddress, persistedAddress);
                CompareAddresses(fakeAddress, persistedAddress);
            }
        }

        [TestMethod]
        public void CanGetByPostalCode()
        {
            var fakeAddress = AddFakeAddress();
            using (var addressRepo = new AddressRepository())
            {
                var persistedAddress = addressRepo.GetByPostalCode(fakeAddress.PostalCode).FirstOrDefault();
                Assert.IsNotNull(persistedAddress);
                Assert.AreNotSame(fakeAddress, persistedAddress);
                CompareAddresses(fakeAddress, persistedAddress);
            }
        }

        public static void CompareAddresses(Address expected, Address actual)
        {
            Assert.AreEqual(expected.AddressLine1, actual.AddressLine1);
            Assert.AreEqual(expected.AddressLine2, actual.AddressLine2);
            Assert.AreEqual(expected.AddressLine3, actual.AddressLine3);
            Assert.AreEqual(expected.AddressLine4, actual.AddressLine4);
            Assert.AreEqual(expected.AddressLine5, actual.AddressLine5);
            Assert.AreEqual(expected.City, actual.City);
            Assert.AreEqual(expected.StateProvince, actual.StateProvince);
            Assert.AreEqual(expected.PostalCode, actual.PostalCode);
            Assert.AreEqual(expected.Country, actual.Country);
            Assert.AreEqual(expected.IsApartmentOrSuite, actual.IsApartmentOrSuite);
            Assert.AreEqual(expected.IsHomeAddress, actual.IsHomeAddress);
            Assert.AreEqual(expected.CreateUserId, actual.CreateUserId);
        }

        private static Address GetMockAddress()
        {
            return new Address
                       {
                           AddressLine1 = "123 Main Street",
                           City = "Anytown",
                           StateProvince = "AS",
                           PostalCode = "12345-6789",
                           Country = "USA",
                           IsApartmentOrSuite = false,
                           IsHomeAddress = true,
                           CreateUserId = "artjohns",
                           CreateDate = DateTime.Now
                       };
        }
    }
}
